package com.bonshotels.DomainLayer.DomainModel;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import org.hibernate.Session;

import com.bonshotels.DataLayer.Hibernate.HibernateUtil;
import com.bonshotels.DomainLayer.CtrlDades.FactoriaCtrlDades;
import com.bonshotels.DomainLayer.CtrlDades.ICtrlBonsHotels;
import com.bonshotels.DomainLayer.CtrlDades.IFactoriaCtrlDades;
import com.bonshotels.Excepcions.BonsHotelsNoExisteix;

/**
 * Classe BonsHotels.
 * 
 * Aquesta classe es singleton i per tant nomes permetra una instancia (RI 1). Com que en la 
 * tercera entrega vam decidir que es responsabilitat de la capa de dades asignar 
 * un indentificador de reserva unic a una Reserva, ja no sha dimplementar el metode
 * getReservationId de BonsHotels que en la primera entrega apareixia en el diagrama 
 * de classes i que utilitzavem al crear una nova reserva. Es public ja que el paquet 
 * de capa de dades ha de poder veure aquesta classe (que esta en un paquet diferent, 
 * Domain Model) per a poder fer el mapeig correctament. Els metodes son publics ja 
 * que es criden des del paquet del servei de pagament amb tarjeta de credit.
 * Com que utilitzem el framework de persistencia
 * Hibernate i aquest utilitza reflexio per fer la seva feina les nostres classes han d'acomplir una
 * serie de propietats perque la reflexio del Hibernate pugui fer completament la seva feina, les
 * classes han de ser publiques, han de tenir un constructor public buit (si no en tenen un d'explicit
 * el per defecte ja ho es), han d'implementar Serializable, i han de tenir substituits (override) els
 * metodes equals() i hashCode() perque identifiquin les classes a partir de la seva clau natural.
 * Com que BonsHotels es un singleton  (nomes te una instancia) i no se li observa cap clau natural s'ha optat per no acomplir
 * aquesta recomanacio del Hibernate, que es util alhora de distingir instancies iguals acabades
 * de crear, ja que la BD encara no els ha assignat la clau artificial, aquesta clau artificial l'hem usat
 *  a l'hora d'implementar equals(), hashCode() i els mapping de Hibernate.
 * @author Jordi Sabater
 */
public class BonsHotels implements Serializable {

	/** La constant serialVersionUID. */
	private static final long serialVersionUID = -4834421507830455364L;
	
	/** L' id. */
	private long id;
	
	/**
	 * Getter de serialversionuid.
	 *
	 * @return the serialversionuid
	 */

	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (int) (id ^ (id >>> 32));
		return result;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		BonsHotels other = (BonsHotels) obj;
		if (id != other.id)
			return false;
		return true;
	}

	/**
	 * Getter de id.
	 *
	 * @return L' id
	 */
	public long getId() {
		return id;
	}

	/**
	 * Getter de id.
	 *
	 * @param id El nou id
	 */
	public void setId(long id) {
		this.id = id;
	}

	/** Diners que lempresa BonsHotels cobra per mantenir un hotel en el seu sistema. */
	private float quotaFixa;
	
	/**
	 * Getter de quota fixa.
	 *
	 * @return la quota fixa
	 */
	public float getQuotaFixa() {
		return quotaFixa;
	}

	/**
	 * Setter de quota fixa.
	 *
	 * @param quotaFixa La nova quota fixa
	 */
	public void setQuotaFixa(float quotaFixa) {
		this.quotaFixa = quotaFixa;
	}

	/**
	 * Getter de quota variable.
	 *
	 * @return La quota variable
	 */
	public float getQuotaVariable() {
		return quotaVariable;
	}

	/**
	 * Setter de quota variable.
	 *
	 * @param quotaVariable La nova quota variable
	 */
	public void setQuotaVariable(float quotaVariable) {
		this.quotaVariable = quotaVariable;
	}

	/** Diners que lempresa BonsHotels cobra per cada reserva realitzada a traves del
	 * seu sistema. */
	private float quotaVariable;
	
	/** Aquesta classe es singleton i per tant cal emmagatzemar la instancia de la 
	 * classe. Com que aquesta classe te atributs que cal fer persistents, quan 
	 * sinvoqui el metode obteInstancia, en cas de que latribut instancia sigui null
	 * perque es la primera vegada que sinvoca, caldra anar al CtrlBonsHotels i demanar
	 * a la capa de dades lunica fila de la taula BonsHotels, que sempre existira. */
	private static BonsHotels instancia = null;
	
	/**
	 * Creadora de BonsHotels. Es privada ja que es singleton i hem de controlar que nomes
	 * i hagi una instancia. Inicialitzem els valors a u ja que en aquesta practica no
	 * els utilitzem en cap operacio, haviem de donar algun valor per que es pugui fer
	 * persistent i no podien violar la RI 10.
	 */
	private BonsHotels() {
		quotaFixa = 1;
		quotaVariable = 1;
	}
	
	/**
	 * Obte instancia.
	 *
	 * @return Retorna la instancia de BonsHotels. Si aquesta es null caldra anar
	 * a buscarla a la capa de dades (la taula BonsHotels sempre te una fila). No 
	 * vam pensar que aquesta classe fos persistent fins a la tercera entrega, es per
	 * aixo que CtrlBonsHotels no apareix en el diagrama de classes de la primera 
	 * entrega pero si que ho comentem en la tercera entrega. Lacces al controlador de 
	 * dades que implementi la interficie ICtrlBonsHotels sera com sempre a traves de
	 * la factoria de controladors. Aixi millorem la canviabilitat i l'acoblament. 
	 * Loperacio obte() de la interficie ICtrlBonsHotels no te parametres ja que 
	 * recordem que la taula BonsHotels de la base de dades nomes tindra una fila.
	 */
	public static BonsHotels obteInstancia() {
		if(instancia == null) {
			IFactoriaCtrlDades fcd = FactoriaCtrlDades.obteInstancia();
			ICtrlBonsHotels cbh = fcd.obteCtrlBonsHotels();
			try {
				instancia = cbh.obte();
			} catch(BonsHotelsNoExisteix BHNEexc) {
				Session session = HibernateUtil.getSessionFactory().getCurrentSession();
				instancia = new BonsHotels();
				session.save(instancia);
			}
		}
		return instancia;
	}
	
	/**
	 * Obte la data actual. Necessari al fer una reserva. Ens ajudem de la classe 
	 * singleton Calendar de java que te un metode que permet obtenir la data actual.
	 *
	 * @return La data actual.
	 */
	public Date obteAvui() {
		Calendar c = GregorianCalendar.getInstance();
		return c.getTime();
	}
	
}
